﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Windows.Controls;
using System.Windows.Threading;
using TangGuo.UserControls;
using TangGuo.Resources;

namespace TangGuo.Views
{
    /// <summary>
    /// Interaction logic for BaoYuZhengBa
    /// </summary>
    public partial class BaoYuZhengBa : UserControl
    {
        const int TotalRow = 4;
        const int TotalCol = 4;
        bool IsMouseLeftDown;
        bool IsMouseLeftUp;
        double DownX;
        double DownY;
        double OffsetX = 0, OffsetY = 0;
        NumberBox[,] Pieces = new NumberBox[TotalCol, TotalRow];
        public BaoYuZhengBa()
        {
            InitializeComponent();
            RestartGame();
        }

        private void RestartGame(object sender, System.Windows.RoutedEventArgs e)
        {
            RestartGame();
        }
        private void RestartGame()
        {
            GameBoard.Children.Clear();
            ScoreText.Text = "";
            for (int i = 0; i < TotalCol; i++)
            {
                for (int j = 0; j < TotalRow; j++)
                {
                    Pieces[i, j] = null;
                }
            }
            Pieces[1, 2] = new(1, 2, 0);
            GameBoard.Children.Add(Pieces[1, 2]);
            Pieces[2, 2] = new(2, 2, 0);
            GameBoard.Children.Add(Pieces[2, 2]);
            Pieces[1, 3] = new(1, 3, 0);
            GameBoard.Children.Add(Pieces[1, 3]);
            Pieces[2, 3] = new(2, 3, 0);
            GameBoard.Children.Add(Pieces[2, 3]);
        }


        /// <summary>
        /// 鼠标在游戏区按下时，记录当前鼠标位置
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void PreMouseDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
        {
            IsMouseLeftDown = true;
            IsMouseLeftUp = false;
            DownX = e.GetPosition(this).X;
            DownY = e.GetPosition(this).Y;
        }
        /// <summary>
        /// 鼠标在游戏区移动时，如果左键处于按下状态，则记录鼠标移动的距离
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void PreMouseMove(object sender, System.Windows.Input.MouseEventArgs e)
        {
            if (IsMouseLeftDown && !IsMouseLeftUp)
            {
                OffsetX = e.GetPosition(this).X - DownX;
                OffsetY = e.GetPosition(this).Y - DownY;
            }
        }

        /// <summary>
        /// 鼠标左键松开时，启动游戏处理程序。
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void PreMouseUp(object sender, System.Windows.Input.MouseButtonEventArgs e)
        {
            if (IsMouseLeftDown && !IsMouseLeftUp && (Math.Abs(OffsetX) > 20 || Math.Abs(OffsetY) > 20))
            {
                for (int i = 0; i < TotalCol; i++)
                    for (int j = 0; j < TotalRow; j++)
                    {
                        if (Pieces[i, j] != null)
                        {
                            if (Pieces[i, j].PieceLevel >= 0) Pieces[i, j].CanJion = true;
                            else {
                                //GameBoard.Children.Remove(Pieces[i, j]);
                                //Pieces[i, j] = null;
                            }
                        }
                    }
            }
            ProcessPieces(OffsetX, OffsetY);
            IsMouseLeftDown = false;
            IsMouseLeftUp = true;
            OffsetX = 0; OffsetY = 0;
        }

        /// <summary>
        /// 根据鼠标拖动的距离，移动或合并宝玉
        /// </summary>
        /// <param name="disx">鼠标水平拖动的距离，正数为向右拖动，负数为向左拖动</param>
        /// <param name="disy">鼠标垂直拖动的距离，正数为向下拖动，负数为向上拖动</param>
        private void ProcessPieces(double disx, double disy)
        {
            int orientation = 0; // 发生移动时，记录移动方向
            if (Math.Abs(disx) > Math.Abs(disy)) // 水平移动量大于垂直移动量时，只水平移动
            {
                if (disx < 0) // 向左移动
                {
                    #region 处理向左移动
                    for (int row = 0; row < TotalRow; row++) // 逐行处理
                    {
                        for (int col = 1; col < TotalCol; col++) // 从第二列开始，逐列处理
                        {
                            if (Pieces[col, row] != null && Pieces[col, row].PieceLevel >= 0)  // 找到一个数字
                            {
                                NumberBox curPie = Pieces[col, row];  // 从当前位置拆下来
                                Pieces[col, row] = null;
                                int targCol = col, targRow = row;
                                for (int i = col - 1; i >= 0; i--) // 向左查找
                                {
                                    if (Pieces[i, targRow] == null) // 前进方向为空则移动到该空位，直到前方位置不为空
                                    {
                                        targCol--;
                                    }
                                }
                                if (targCol > 0)    // 如果未出边界，说明前进方向不为空，则判断该位置的情况
                                {
                                    if (curPie.PieceLevel < 10 // 如果数字未达到10
                                        && Pieces[targCol - 1, targRow].PieceLevel == curPie.PieceLevel // 且两个数字相同
                                        && Pieces[targCol - 1, targRow].CanJion == true) // 且目标位置数字可以合并。些标志用于防止在一轮中发生二次合并。
                                    {
                                        targCol--;
                                    }
                                }

                                if (targCol != col) // 如果与原位置不同
                                {
                                    if (Pieces[targCol, targRow] != null)  // 如果该位置不为空（意味着两个数字相同）
                                    {
                                        Pieces[targCol, targRow].SetNewLevel(-1);
                                        Pieces[targCol, targRow].MoveBoxTo(targCol, targRow); // 将该位置的数字设为-1，在动画结束后会自动隐藏，系统将作为垃圾回收。
                                        curPie.SetNewLevel(curPie.PieceLevel + 1);
                                        curPie.CanJion = false;
                                    }
                                    curPie.MoveBoxTo(targCol, targRow);  // 移动动画
                                    orientation = 1;
                                }
                                Pieces[targCol, targRow] = curPie; // 挂接到目标位置

                            }
                        }
                    }
                    #endregion
                }
                else // 向右移动
                {
                    #region 处理向右移动
                    for (int row = 0; row < TotalRow; row++) // 逐行处理
                    {
                        for (int col = TotalCol - 2; col >= 0; col--) // 从倒数第二列开始，向前逐列处理
                        {

                            if (Pieces[col, row] != null && Pieces[col, row].PieceLevel >= 0)  // 找到一个数字
                            {
                                NumberBox curPie = Pieces[col, row];
                                Pieces[col, row] = null;
                                int targCol = col, targRow = row;
                                for (int i = col + 1; i < TotalCol; i++) // 向右查找
                                {
                                    if (Pieces[i, row] == null) // 为空则移动
                                    {
                                        targCol++;
                                    }
                                }
                                if (targCol < (TotalCol - 1))    // 如果未出边界，说明前进方向不为空，则判断该位置的情况
                                {
                                    if (curPie.PieceLevel < 10 // 如果数字未达到10
                                        && Pieces[targCol + 1, row].PieceLevel == curPie.PieceLevel // 且两个数字相同
                                        && Pieces[targCol + 1, row].CanJion == true) // 且目标位置数字可以再合并。
                                    {
                                        targCol++;
                                    }
                                }
                                if (targCol != col)
                                {
                                    if (Pieces[targCol, targRow] != null)
                                    {
                                        Pieces[targCol, targRow].SetNewLevel(-1);
                                        Pieces[targCol, targRow].MoveBoxTo(targCol, targRow);
                                        curPie.SetNewLevel(curPie.PieceLevel + 1);
                                        curPie.CanJion = false;
                                    }
                                    curPie.MoveBoxTo(targCol, targRow);  // 移动动画
                                    orientation = 2;
                                }
                                Pieces[targCol, targRow] = curPie; // 挂接到目标位置
                            }
                        }
                    }
                    #endregion
                }
            }
            else // 垂直移动
            {
                if (disy < 0) // 向上移动
                {
                    #region 处理向上移动
                    for (int col = 0; col < TotalCol; col++) // 逐列处理
                    {
                        for (int row = 1; row < TotalRow; row++) // 从第二行开始，向下逐列处理
                        {
                            if (Pieces[col, row] != null && Pieces[col, row].PieceLevel >= 0)  // 找到一个数字
                            {
                                NumberBox curPie = Pieces[col, row];
                                Pieces[col, row] = null;
                                int targCol = col, targRow = row;
                                for (int i = row - 1; i >= 0; i--) // 向上查找
                                {
                                    if (Pieces[targCol, i] == null) // 为空则移动
                                    {
                                        targRow--;
                                    }
                                }
                                if (targRow > 0)    // 如果未出边界，说明前进方向不为空，则判断该位置的情况
                                {
                                    if (curPie.PieceLevel < 10 // 如果数字未达到10
                                        && Pieces[targCol, targRow - 1].PieceLevel == curPie.PieceLevel // 且两个数字相同
                                        && Pieces[targCol, targRow - 1].CanJion == true) // 且目标位置数字可以再合并。
                                    {
                                        targRow--;
                                    }
                                }

                                if (targRow != row)
                                {
                                    if (Pieces[targCol, targRow] != null)
                                    {
                                        Pieces[targCol, targRow].SetNewLevel(-1);
                                        Pieces[targCol, targRow].MoveBoxTo(targCol, targRow);
                                        curPie.SetNewLevel(curPie.PieceLevel + 1);
                                        curPie.CanJion = false;
                                    }
                                    curPie.MoveBoxTo(targCol, targRow);  // 移动动画
                                    orientation = 3;
                                }
                                Pieces[targCol, targRow] = curPie; // 挂接到目标位置
                            }
                        }
                    }
                    #endregion
                }
                else // 向下移动
                {
                    #region 处理向下移动
                    for (int col = 0; col < TotalCol; col++) // 逐列处理
                    {
                        for (int row = TotalRow - 2; row >= 0; row--) // 从倒数第二行开始，向上逐列处理
                        {
                            if (Pieces[col, row] != null && Pieces[col, row].PieceLevel >= 0)  // 找到一个数字
                            {
                                NumberBox curPie = Pieces[col, row];
                                Pieces[col, row] = null;
                                int targCol = col, targRow = row;
                                for (int i = row + 1; i < TotalRow; i++) // 向下查找
                                {
                                    if (Pieces[targCol, i] == null) // 为空则移动
                                    {
                                        targRow++;
                                    }
                                }
                                if (targRow < (TotalRow - 1))    // 如果未出边界，说明前进方向不为空，则判断该位置的情况
                                {
                                    if (curPie.PieceLevel < 10 // 如果数字未达到10
                                        && Pieces[targCol, targRow + 1].PieceLevel == curPie.PieceLevel // 且两个数字相同
                                        && Pieces[targCol, targRow + 1].CanJion == true) // 且目标位置数字可以再合并。
                                    {
                                        targRow++;
                                    }
                                }
                                if (targRow != row)
                                {
                                    if (Pieces[targCol, targRow] != null)
                                    {
                                        Pieces[targCol, targRow].SetNewLevel(-1);
                                        Pieces[targCol, targRow].MoveBoxTo(targCol, targRow);
                                        curPie.SetNewLevel(curPie.PieceLevel + 1);
                                        curPie.CanJion = false;
                                    }
                                    curPie.MoveBoxTo(targCol, targRow);  // 移动动画
                                    orientation = 4;
                                }
                                Pieces[targCol, targRow] = curPie; // 挂接到目标位置
                            }
                        }
                    }
                    #endregion
                }
            }
            //Thread.Sleep(sleepTime);
            if (orientation is >= 1 and <= 4) AddNewNumber(orientation);  // 如发生了数字移动，则是添加一个新数字
            GetScore();
        }


        /// <summary>
        /// 在移动方向的后方，新增一个宝玉
        /// </summary>
        /// <param name="orientation">最后一次移动的方向</param>
        private void AddNewNumber(int orientation)
        {
            int col1 = 0, col2 = TotalCol - 1, row1 = 0, row2 = TotalRow - 1;
            switch (orientation)
            {
                case 1: // 发生了向左移动，在右边两列增加新数字
                    col1 = TotalCol - 2;
                    col2 = TotalCol - 1;
                    break;
                case 2: // 发生了向右移动，在左边两列增加新数字
                    col1 = 0;
                    col2 = 1;
                    break;
                case 3: // 发生了向上移动，在下边两行增加新数字
                    row1 = TotalRow - 2;
                    row2 = TotalRow - 1;
                    break;
                case 4: // 发生了向下移动，在上边两行增加新数字
                    row1 = 0;
                    row2 = 1;
                    break;
                default: break;
            }
            ArrayList freePosList = new ArrayList(); // 用于存放在周边找到的空的坐标空置
            for (int i = col1; i <= col2; i++)
            {
                for (int j = row1; j <= row2; j++)
                {
                    if (Pieces[i, j] == null)
                    {
                        freePosList.Add(new Pos(i, j));  // 找出周边的空位置，添加到列表中。
                    }
                }
            }

            if (freePosList.Count == 0) return;  // 如果没有找到空位

            Random random = new Random();
            int[] newPieList = { 0, 1, 0, 1, 0, 2, 0, 1, 0, 1, 0, 2, 0, 1, 0, 1, 0, 2 };  // 新增加的宝玉，候选列表，0、1、2概率抽中的不同
            int newNum = newPieList[random.Next(0, newPieList.Length)]; // 从候选列表中随机抽一个
            if(freePosList.Count <5 ) { newNum %= 3; } // 空位较少时，减小宝玉数值，以降低难度

            int index = random.Next(0, 100) % freePosList.Count; // 生成随机索引位置，从坐标数组列表中随机抽取一个坐标
            Pos pos = freePosList[index] as Pos;
            int col = pos.Col;
            int row = pos.Row;

            Pieces[col, row] = new(col, row, newNum);
            GameBoard.Children.Add(Pieces[col, row]);

            // 此处可添加判断游戏结束的代码。如仅还有一个空位，且新添加的数字与上下左右数字都不相同，则游戏结束。

        }
        private void GetScore()
        {
            long score = 0;
            int[] pieValue = { 0, 10, 30, 80, 200, 500, 1200, 2800, 6000, 14000, 30000 };
            for (int row = 0; row < TotalRow; row++) // 逐行处理
            {
                for (int col = 0; col < TotalCol; col++) // 从第二列开始，逐列处理
                {
                    if (Pieces[col, row] != null && Pieces[col, row].PieceLevel >= 0)
                    {
                        score += pieValue[Pieces[col, row].NewLevel];
                    }
                }
            }
            ScoreText.Text = score.ToString();
        }


        /// <summary>
        /// 对宝玉按大小进行排序
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void ReSort(object sender, System.Windows.RoutedEventArgs e)
        {
            List<NumberBox> boxList = new List<NumberBox>();
            for (int row = 0; row < TotalRow; row++)  // 将宝玉存放到列表中，便于排序
            {
                for (int col = 0; col < TotalCol; col++)
                {
                    if (Pieces[col, row] != null && Pieces[col, row].PieceLevel >= 0)
                    {
                        boxList.Add(Pieces[col, row]);
                    }
                    Pieces[col, row] = null;
                }
            }
            boxList.Sort(); // 对列表排序，NumberBox类中已定义了排序规则，为从大到小排序
            for (int i = 0; i < boxList.Count; i++) // 将排序完成后的宝玉，从大到小逐个放到指定位置
            {
                int col=i% TotalCol; int row=i/ TotalCol; // 根据序号，计算出坐标位置
                Pieces[col, row] = boxList[i];
                Pieces[col, row].MoveBoxTo(col, row);
            }
        }

    }
}
